/**
 * @author Marcos Portnoi
 * @date July 2013
 * 
 * @copyright Copyright (C) 2013 University of Delaware.
 * @copyright QCNSim uses elements of TARVOS simulator, Copyright (C) 2005, 2006, 2007 Marcos Portnoi.
 * @par
 * This file is part of QCNSim.  QCNSim is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.<br>
 * QCNSim is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.<br>
 * You should have received a copy of the GNU Lesser General Public License
 * along with QCNSim.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "Entity.h"
#include "Scheduler.h"
#include "SimulatorGlobals.h"
#include "Token.h"
#include "EventType.h"
#include "ProtocolDataUnit.h"
#include <memory>

/**
 * @brief TrafficGenerator parent class.
 * 
 * @par Description
 * The Traffic Generator class is a parent class for classes that generate traffic for the simulator. A traffic generator is typically
 * an event generator, which generates events in time distributed according to some probability distribution.
 * For instance, we would have exponential traffic generator, constant traffic generator, pareto traffic generator, gaussian traffic generator, random traffic generator.
 *
 * The Traffic Generator is also a child of Entity abstract class, such that Traffic Generators can be included as entities into tokens, events, etc.
 * Common, for all child classes, are reference members to scheduler, such that the traffic generators can schedule their events directly.
 *
 */
class TrafficGenerator: public Entity {
protected:
	Scheduler &scheduler;	//!< Reference to Scheduler object, such that traffic generators may schedule their events.
	SimulatorGlobals &simulatorGlobals;  //!< Reference to SimulatorGlobals object, to get random generator info
	EventType eventType; //!< Event type that this generator will produce.
	std::shared_ptr<Entity> tokenContents;  //!< Reference to Entity object that will be carried by the token.
	std::shared_ptr<Entity> source; //!< Entity to which the generator is attached (to which tokens are generated).
	std::shared_ptr<Entity> destination; //!< Destination entity, to which the generated tokens will be sent.
	int priority;  //!< Token priority. Higher priority, higher number.
	bool isOn; //!< True if generator is on (and generating traffic); false if generator is off.
	unsigned int tokensGeneratedCount; //!< Count of tokens (events) generated by this traffic generator.
	
	TrafficGenerator(SimulatorGlobals &simulatorGlobals, Scheduler &scheduler, EventType eventType, std::shared_ptr<Entity> tokenContents,
		std::shared_ptr<Entity> source, std::shared_ptr<Entity> destination, int priority);
	TrafficGenerator(SimulatorGlobals &simulatorGlobals, Scheduler &scheduler, EventType eventType, std::shared_ptr<Entity> tokenContents,
		std::shared_ptr<Entity> source, std::shared_ptr<Entity> destination, int priority, unsigned int seed);

	virtual std::shared_ptr<Token> createInstanceTrafficEvent(bool recordRoute = false) =0; // Pure virtual, must be implemented by child classes.
	virtual std::shared_ptr<Token> createInstanceTrafficEvent(std::shared_ptr<Entity> tokenContents, bool recordRoute = false) =0; // Pure virtual, must be implemented by child classes.
	virtual std::shared_ptr<Token> createInstanceTrafficEvent(std::vector<std::shared_ptr<Entity>> explicitRoute, bool recordRoute = false) =0; // Pure virtual, must be implemented by child classes.
	virtual std::shared_ptr<Token> createInstanceTrafficEvent(std::shared_ptr<Entity> tokenContents, std::vector<std::shared_ptr<Entity>> explicitRoute, bool recordRoute = false) =0; // Pure virtual, must be implemented by child classes.
	virtual std::shared_ptr<ProtocolDataUnit> createInstanceTrafficEventPdu(unsigned int pduSize, bool recordRoute = false) =0;
	virtual std::shared_ptr<ProtocolDataUnit> createInstanceTrafficEventPdu(unsigned int pduSize, std::shared_ptr<Entity> tokenContents, bool recordRoute = false) =0;
	virtual std::shared_ptr<ProtocolDataUnit> createInstanceTrafficEventPdu(unsigned int pduSize, std::vector<std::shared_ptr<Entity>> explicitRoute, bool recordRoute = false) =0;
	virtual std::shared_ptr<ProtocolDataUnit> createInstanceTrafficEventPdu(unsigned int pduSize, std::shared_ptr<Entity> tokenContents, std::vector<std::shared_ptr<Entity>> explicitRoute, bool recordRoute = false) =0;

public:
	virtual void turnOn();
	virtual void turnOff();
	virtual void setTokenContents(std::shared_ptr<Entity> tokenContents);
	virtual unsigned int getTokensGeneratedCount() const;
	virtual EventType getEventType() const;
	virtual void setEventType(EventType eventType);
	virtual std::shared_ptr<Entity> getTokenContents() const;
	virtual std::shared_ptr<Entity> getSource() const;
	virtual void setSource(std::shared_ptr<Entity> source);
	virtual std::shared_ptr<Entity> getDestination() const;
	virtual void setDestination(std::shared_ptr<Entity> destination);
};